/*
** A Driver for a variety of GP classification algorithms
*/

/* TODO
    - do mpi enabled cross validation 
*/

// third party includes
#include <mpi.h>
#include <string>
#include <map>
#include <set>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <strings.h>

// local includes
#include <crf_sequence/crf_learn.h>
#include <crf_sequence/param.h>
#include <crf_sequence/sparse_array.h>
#include <crf_sequence/util.h>
#include <crf_sequence/data.h>
#include "st_cmdline.h"
#include "st_classifier.h"

#include "detect_cliques.h"
#include "cmdline.h"

static const char *REVISION = "$Revision: 1.8 $";

int main(int argc, char **argv)
{
    MPI_Init(&argc,&argv);
    int rank, size;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    if (rank == 0)
    {
        std::cout << "Super-tagging CRF algorithms: Copyright 2006 Phil Blunsom\n";
        std::cout << REVISION << '\n' << std::endl;
    }
    // this parameter stores global config info
    boost::shared_ptr<GPParameter> param(new GPParameter);

    // process command line args
    char *vector_test_file=0, *output_file=0;
    bool debug=false; 
    std::string param_file="";

    // process cmdline
    gengetopt_args_info args_info;
    if (cmdline_parser (argc, argv, &args_info) != 0)
        return EXIT_FAILURE;
//    if (cmdline_parser_configfile(args_info.conf_file_arg, &args_info, 1, 0, 1) != 0)
//        return EXIT_FAILURE;

    if(args_info.verbose_given)        debug = true;
    if(args_info.model_given)          param_file = args_info.model_arg;
    if(args_info.vector_test_given)    vector_test_file = args_info.vector_test_arg;
    output_file = args_info.output_arg;

    param->debug = debug;

    double *alpha=0;
    std::ifstream fd(param_file.c_str());
    int alpha_length=0;
    if (fd.good())
    {
        if (rank == 0)
            std::cout << "--- Setting initial parameters from " << param_file
                      << std::endl;
    
        // read the parameters from the file
        deserialise1d(fd, alpha, alpha_length);
        fd.close();
    }
	boost::shared_array<double> weights(alpha);
    STClassifierPtr classifier(new STClassifier(weights, param));

//    if (rank == 0)
    {
        // test accuracy
        // load the testing data
        if (rank==0) std::cout << "\nRoot process decoding: " << std::endl;  
        EvaluationPtr result;
        boost::shared_ptr<Parameters> config(new Parameters);
        if (args_info.st_conf_given &&
            align_parser_configfile(args_info.st_conf_arg, config.get(), 1, 1, 1) 
			!= 0)
        {
                std::cerr << "Config parser error" << std::endl;
                return EXIT_FAILURE;
        }

        // set the segment of the data that each MPI process should load
        int mpi_start = (config->sentences_arg / size)*rank;
        int mpi_end=0;
        if (rank == size-1) mpi_end = config->sentences_arg;
        else mpi_end = (config->sentences_arg / size)*(rank+1);

        char rank_str[20];
        sprintf(rank_str,"%d",(int)rank);
        std::string tmp_out = std::string(".rank_")+rank_str+"_"+output_file;

        CliqueDetectorPtr clique_detector(new CliqueDetector(config));
        result = classifier->evaluate(clique_detector, alpha_length,
                    tmp_out, mpi_end-mpi_start, mpi_start, args_info.viterbi_given);

        int total_cliques = result->tp+result->fp;
        if (rank==0) 
        {
            std::cout << std::setprecision(4) << "Total accuracy over " 
                << total_cliques << " events: " 
                << (float)result->tp/total_cliques*100.0 << '%' << std::endl;
            std::cout << result->tp << std::endl;
        }
        // clean up memory

        MPI_Barrier(MPI_COMM_WORLD);
        if (rank==0) 
        {
            std::stringstream ss;
            ss << "cat";
            for (int i=0; i<size; ++i)
                ss << " .rank_" << i << "_" << output_file;
            std::string command = ss.str() + ">" + output_file;
            std::cout << command << std::endl;
            system(command.c_str());
            command = std::string("rm .*_") + output_file;
            system(command.c_str());
        }
    }

    MPI_Finalize();
    return 0;
}
